package com.redsoft.spirit.config;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.net.ConnectException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import com.redsoft.spirit.entity.JsonResult;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import javassist.NotFoundException;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;

@ControllerAdvice
public class GlobalExceptionHandler {
	
    //定义一个全局的记录器，通过LoggerFactory获取
    private final static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
	
	/**
	 * 
	 * 抓校验时候出现的异常.
	 * <pre>
	 * 	抓校验时候出现的异常
	 * </pre>
	 * 
	 * @author 杨雷
	 * @param e
	 * @param response
	 * @return
	 */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody //在返回自定义相应类的情况下必须有，这是@ControllerAdvice注解的规定
    public JsonResult exceptionHandler(ConstraintViolationException e, HttpServletResponse response) {
    	JsonResult result = new JsonResult();
    	
    	//异常的代码以-200开始
    	result.setStatus(-200);

//    	System.out.println(e.getConstraintViolations());
    	
    	Set<ConstraintViolation<?>> validResult = e.getConstraintViolations();
    	
        if (null != validResult && validResult.size() > 0) {
            StringBuilder sb = new StringBuilder();
            for (Iterator<ConstraintViolation<?>> iterator = validResult.iterator(); iterator.hasNext();) {
                ConstraintViolation<Object> constraintViolation = (ConstraintViolation<Object>) iterator.next();
                
                //这里只取注解里的错误消息
//                sb.append(constraintViolation.getMessage()).append("、");
                sb.append(constraintViolation.getMessage());
                
                break;
            }
            
            if(sb.lastIndexOf("、") == sb.length()-1){
                sb.delete(sb.length()-1, sb.length());
            }
            
            result.setMsg(sb.toString());
        }

        return result;
    }
    
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public String defaultErrorHandler(HttpServletRequest request, Exception e) throws Exception {
//        logger.error("---DefaultException Handler---Host {} invokes url {} ERROR: {}", req.getRemoteHost(), req.getRequestURL(), e.getMessage());
    	System.out.println("这个异常也能抓一次nneng maa？" + e.getMessage());
    	e.printStackTrace();
    	String message = handle(e);
    	
        return new JsonResult(null, message).failure().toString();
    }
    
    public String handle(Exception e) {
  	  
//		// 出现异常的目标方法参数
//		Object[] args = e.getArgs();
//
//		// 出现异常的目标方法
//		Method method = e.getMethod();
//
//		// 出现异常的目标类
//		Object targetClass = e.getTarget();
//		
//		short errorCode = 200;
//				
    	String message = null;
    	
		Throwable throwableFirst = e.getCause();
		Throwable throwableLast = handleCause(e);
//		
//		Map < String, String> nameMap = logError(targetClass, method, throwableLast);


		// 出现异常的名字
		String exceptionName = throwableLast.getClass().getName();
  	  
		// 在这里判断异常，根据不同的异常返回错误。
		if (exceptionName.equals(DataAccessException.class.getName())) {
			// ex.printStackTrace();
			// throw new BusiException("数据库操作失败！");
			message = "数据库操作失败";
			
			logger.error("数据库操作失败！");
		} else if (exceptionName.equals(NullPointerException.class.getName())) {
		
//			// 空指针异常的话，处理出异常的参数
//			String[] argsNameAop = getArgsName(targetClass.getClass().getName(), method.getName());
//		
//			Map argsMap = new HashMap< String, Object>();
//			
//			for (int i = 0; i < args.length; i++) {
//				argsMap.put(argsNameAop[i], args[i]);
//			}
//			String[] argsNameEx = getArgsName(nameMap.get("clazzName"), nameMap.get("methodName"));
//			
//			for (String nameEx : argsNameEx) {
//				if (argsMap.get(nameEx) == null) {
//					logger.error("参数" + nameEx + " 的值为null");
//				}
//			}
					
			message = "空指针异常！";
			logger.error("空指针异常！");
		} else if (exceptionName.equals(IOException.class.getName())) {
		
		//			throw new BusiException("IO异常！");
			message = "IO异常！";
			logger.error("IO异常！");
		} else if (exceptionName.equals(ClassNotFoundException.class.getName())) {
		
		//			throw new BusiException("指定的类不存在！");
			message = "指定的类不存在！";
			logger.error("指定的类不存在！");
		} else if (exceptionName.equals(ArithmeticException.class.getName())) {
		
		//			throw new BusiException("数学运算异常！");
			message = "数学运算异常！";
			logger.error("数学运算异常！");
		} else if (exceptionName.equals(ArrayIndexOutOfBoundsException.class.getName())) {
		
		//			throw new BusiException("数组下标越界!");
			message = "数组下标越界！";
			logger.error("数组下标越界！");
		} else if (exceptionName.equals(IllegalArgumentException.class.getName())) {
		
		//			throw new BusiException("方法的参数错误！");
			message = "方法的参数错误！";
			logger.error("方法的参数错误！");
		} else if (exceptionName.equals(ClassCastException.class.getName())) {
		
		//			throw new BusiException("类型强制转换错误！");
			message = "类型强制转换错误！";
			logger.error("类型强制转换错误！");
		} else if (exceptionName.equals(SecurityException.class.getName())) {
		
		//			throw new BusiException("违背安全原则异常！");
			message = "违背安全原则异常！";
			logger.error("违背安全原则异常！");
		} else if (exceptionName.equals(SQLException.class.getName())) {
		
		//			throw new BusiException("操作数据库异常！");
			message = "操作数据库异常！";
			logger.error("操作数据库异常！");
		} else if (exceptionName.equals(NoSuchMethodError.class.getName())) {
		
		//			throw new BusiException("方法末找到异常！");
			message = "方法未找到！";
			logger.error("方法未找到");
		} else if (exceptionName.equals(InternalError.class.getName())) {
		
		//			throw new BusiException("Java虚拟机发生了内部错误");
			message = "Java虚拟机发生了内部错误！";
			logger.error("Java虚拟机发生了内部错误");
		} else if (exceptionName.equals(ConnectException.class.getName())) {
			
			//			throw new BusiException("Java虚拟机发生了内部错误");
				message = "系统暂时不通，请稍后重试！";
				logger.error("系统暂时不通，请稍后重试！");
		} else if (exceptionName.equals(RuntimeException.class.getName())) {
			
			//			throw new BusiException("Java虚拟机发生了内部错误");
				message = "系统暂时不通，请稍后重试！";
				logger.error("系统暂时不通，请稍后重试！");
		} else {
			message = e.getMessage();
		}

		return message;
  }
//  
//  
//	/**
//	 * 
//	 * 根据传入的类名和方法名获取方法中的参数的名称数组.
//	 * <pre>
//	 * 	根据传入的类名和方法名获取方法中的参数的名称数组
//	 * </pre>
//	 * 
//	 * @author 杨雷
//	 * @param clazzName
//	 * @param methodName
//	 * @return
//	 */
//	public String[] getArgsName(String clazzName, String methodName) {
//		try {
//			ClassPool pool = ClassPool.getDefault();
//						
//			try {
//				//pool.insertClassPath("E:\\redsoft\\PETS\\pets\\WEB-INF\\lib\\redsoft_pets_user-1.0-SNAPSHOT.jar");
//				pool.getCtClass(clazzName);
//			} catch (Exception e) {
//				
//				//获取系统的lib目录
//				String path = Thread.currentThread().getContextClassLoader().getResource("").toString();
//				//path = path.replace('/', '\\'); // 将/换成\  
//				path = path.replace("file:/", ""); //去掉file:  
//				path = path.replace("classes/", ""); //去掉class\ 
//				path = path + "lib";
//				
//				List < String > lstNames = getFileName(path);
//				
//				for (String string : lstNames) {
//					pool.insertClassPath(path + "/" + string);
//				}
//				
//				getArgsName(clazzName, methodName);
//			}
//			
//
//			
////			pool.insertClassPath(path); 
//			CtClass cc = pool.getCtClass(clazzName);
//			
//			CtMethod[] method = cc.getDeclaredMethods();
//			
//			CtMethod cm = cc.getDeclaredMethod(methodName);
//			
//
//			// 使用javaassist的反射方法获取方法的参数名
//			MethodInfo methodInfo = cm.getMethodInfo();
//			CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
//			LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
//			if (attr == null) {
//				// exception
//			}
//			String[] paramNames = new String[cm.getParameterTypes().length];
//			int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
//			for (int i = 0; i < paramNames.length; i++){
//				paramNames[i] = attr.variableName(i + pos);
//				//System.out.println(paramNames[i]);
//			}
//			
//			return paramNames;
////			// paramNames即参数名
////			for (int i = 0; i < paramNames.length; i++) {
////				System.out.println(paramNames[i]);
////			}
//
//		} catch (NotFoundException e) {
//			e.printStackTrace();
//			
//			return null;
//		}
//	}
//	
//	/**
//	 * 
//	 * 记录异常的错误日志.
//	 * <pre>
//	 * 	记录异常的错误日志,根据堆栈里的信息来查询错误的源头
//	 * </pre>
//	 * 
//	 * @author 杨雷
//	 * @param target
//	 * @param method
//	 * @param e
//	 */
//	public Map logError(Object target, Method method, Throwable e) {
//		
//		Map < String, String > namesMap = new HashMap<>();
//		//取出堆栈内的异常信息
//		StringBuffer sb = new StringBuffer(); 
//
//		ByteArrayOutputStream baos = new ByteArrayOutputStream();  
//		e.printStackTrace(new PrintStream(baos));  
//		String exception = baos.toString();  
//		sb.append(exception);
//		
//		try {
//			baos.close();
//		} catch (IOException ioe) {
//
//		}
//		
//		String s = sb.toString().substring(sb.toString().indexOf("com.redsoft.")) ;
//		   
//		String ss = s.substring(s.indexOf("com.redsoft."), s.indexOf(".java:"));
//		String clazzNameLong = ss.substring(0, ss.lastIndexOf(".")); 
//		String clazzName = ss.substring(ss.indexOf("(") + 1);
//		String methodNameLong = s.substring(s.indexOf("com.redsoft."), s.indexOf("("));
//		String methodName = methodNameLong.substring(methodNameLong.lastIndexOf(".") + 1);
//
////		
////		if (!clazzName.equals(target.getClass().getName()) || !methodName.equals(method.getName())) {
////			
////			
////		}
//		XLogger.getLogger().error("异常所在java类: " + clazzNameLong);
//		XLogger.getLogger().error("异常所在method: " + methodName);
//		namesMap.put("clazzName", clazzNameLong);
//		namesMap.put("methodName", methodName);
//		
//		String rootErrorRegEx = clazzName + "." + methodName + "(.*)";
//		Pattern patRoot = Pattern.compile(rootErrorRegEx); 
//		Matcher matRoot = patRoot.matcher(sb); 
//		
//		while (matRoot.find()) {
//			//System.out.println(matRoot.group(0));
//			String firstLine = matRoot.group(0);
//			XLogger.getLogger().error("异常所在行数：" + Pattern.compile("[^0-9]").matcher(firstLine).replaceAll(""));			
//		}
//				
//		String regEx = "Caused by:(.*)";    
//		Pattern pat = Pattern.compile(regEx);    
//		Matcher mat = pat.matcher(sb);   
//		
//		while (mat.find()) { 
//			int count = mat.groupCount();
//			
//			for (int i =1; i <= count ; i++) {
//				XLogger.getLogger().error("异常原因：" + mat.group(i));
//			}
//		}
//		XLogger.getLogger().info(sb);
//		
//		return namesMap;
//	}
//	
//	private List<String> getFileName(String path) {
//
//		File file = new File(path);
//
//		File[] array = file.listFiles();
//		List<String> fileNames = new ArrayList<>();
//
//		for (int i = 0; i < array.length; i++) {
//			if (array[i].isFile()) {
//
//				String fileName = array[i].getName();
//
//				if (fileName.indexOf("redsoft") != -1) {
//					fileNames.add(array[i].getName());
//					//System.out.println(array[i].getName());
//				}
//			}
//		}
//
//		return fileNames;
//	}
//	
	public Throwable handleCause(Throwable e) {
		if (e.getCause() != null) {
			return handleCause(e.getCause());
		}else {
			return e;
		}
	}

}